package com.jplus.core.mvc;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jplus.core.bean.BeanHandle;
import com.jplus.core.core.fault.InitializationError;
import com.jplus.core.mvc.action.Handler;
import com.jplus.core.mvc.action.Requester;
import com.jplus.core.mvc.annotation.Controller;
import com.jplus.core.mvc.annotation.Request;
import com.jplus.core.util.FormatUtil;
import com.jplus.core.util.SecurityUtil;

/**
 * ActionHandle
 * 
 * @author Yuanqy
 *
 */
public class ActionHandle {
	private static final Logger logger = LoggerFactory.getLogger(ActionHandle.class);
	private static final Map<Requester, Handler> actionMap = new LinkedHashMap<Requester, Handler>();
	private static final Map<String, Method> actionFixMethod = new HashMap<String, Method>();
	static {
		try {
			Set<Class<?>> beanSet = BeanHandle.beanSet;
			for (Class<?> cls : beanSet) {
				if (cls.isAnnotationPresent(Controller.class)) {
					// 遍历 Action 类
					Method[] actionMethods = cls.getDeclaredMethods();
					for (Method actionMethod : actionMethods) {
						handleActionMethod(cls, actionMethod);
					}
				}
			}
		} catch (Exception e) {
			logger.error("Action 初始化失败：", e);
			throw new InitializationError(e);
		}
	}

	private static void handleActionMethod(Class<?> actionClass, Method actionMethod) {
		// 判断当前 Action 方法是否带有 Request 注解
		String actionPath = null, requestMethod = null;
		if (actionMethod.isAnnotationPresent(Request.Get.class)) {
			actionPath = actionMethod.getAnnotation(Request.Get.class).value();
			requestMethod = "GET";
		} else if (actionMethod.isAnnotationPresent(Request.Post.class)) {
			actionPath = actionMethod.getAnnotation(Request.Post.class).value();
			requestMethod = "POST";
		} else if (actionMethod.isAnnotationPresent(Request.Put.class)) {
			actionPath = actionMethod.getAnnotation(Request.Put.class).value();
			requestMethod = "PUT";
		} else if (actionMethod.isAnnotationPresent(Request.Delete.class)) {
			actionPath = actionMethod.getAnnotation(Request.Delete.class).value();
			requestMethod = "DELETE";
		} else if (actionMethod.isAnnotationPresent(Request.All.class)) {
			actionPath = actionMethod.getAnnotation(Request.All.class).value();
			requestMethod = "ALL";
		} else if (actionMethod.isAnnotationPresent(Request.Prefix.class)) {
			requestMethod = "Prefix";
		} else if (actionMethod.isAnnotationPresent(Request.Suffix.class)) {
			requestMethod = "Suffix";
		}
		if (requestMethod != null && actionPath == null)
			actionFixMethod.put(SecurityUtil.Encrypt(actionClass.getName() + requestMethod, "SHA-256"), actionMethod);
		if (requestMethod == null || actionPath == null)
			return;
		Request req = actionClass.getAnnotation(Request.class);
		if (req != null)
			actionPath = FormatUtil.toString(req.value()) + FormatUtil.toString(actionPath);
		actionPath = FormatUtil.formatPath("/" + actionPath);
		actionMethod.setAccessible(true); // 取消类型安全检测（可提高反射性能）
		addActionMap(new Requester(requestMethod, actionPath), new Handler(actionClass, actionMethod, actionPath));
	}

	/**
	 * 手动追加Action
	 */
	public static void addActionMap(Requester req, Handler hand) {
		logger.info("\tAction[{}]:[{}]\t{}.{}()", req.getRequestMethod(), req.getRequestPath(), hand.getActionClass().getName(), hand.getActionMethod().getName());
		actionMap.put(req, hand);
	}

	/**
	 * 获取 Action Map
	 */
	public static Map<Requester, Handler> getActionMap() {
		return actionMap;
	}

	/**
	 * 执行Action 前、后缀方法
	 */
	public static void doActionfixMethod(Class<?> action, Object actionInstance, String type) {
		Method m = null;
		try {
			m = actionFixMethod.get(SecurityUtil.Encrypt(action.getName() + type, "SHA-256"));
			if (m != null)
				m.invoke(actionInstance, new Object[] {});
		} catch (Exception e) {
			logger.error("An error occurs when the request execution " + type + " method:{},{}", m, action);
			logger.error("Exception:", e);
		}
	}
}
